
package gameserver;

import common.SharedBuffer;
import common.packet.BodyState;
import common.packet.ClientInfo;
import common.packet.Input;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jbox2d.common.Vec2;

/**
 * Physics thread modified implementation for the game server. In its preStep()
 * method it applies user input if any. In its postStep() method it writes the
 * current configuration of the physiscs world into its physicsOutput
 * SharedBuffer which can later be read off through the getPhysicsOutput method.
 *
 * @author xissburg
 */
public class PhysicsThreadS extends common.PhysicsThread
{
    private Game game;
    private SharedBuffer<Collection<BodyState>> physicsOutput;
    private Map<String, Vec2> preStepForces;

    public PhysicsThreadS(Game game) {
        this.game = game;
        physicsOutput = new SharedBuffer<Collection<BodyState>>();
        preStepForces = new HashMap<String, Vec2>();
    }

    public Collection<BodyState> getPhysicsOutput(boolean wait) throws InterruptedException {
        return physicsOutput.get(wait);
    }
    
    @Override
    protected void preStep()
    {
        Collection<ClientThread> clients = game.getClients();
        final long maxTime = 50;

        for(ClientThread ct: clients)
        {
            if(ct.getClient().getClientInfo().getType() == ClientInfo.Type.SPECTATOR)
                continue;
            
            List<Input> inputList = ct.getInput();
            
            if(inputList != null && !inputList.isEmpty())
            {
                Point disp = inputList.get(0).getDisplacement();

                String name = ct.getClient().getClientInfo().getName();
                Vec2 force = physicsWorld.computeForceFromDisplacement(disp.x, disp.y);
                physicsWorld.applyTimedForceOnBody(name, force, maxTime);
                preStepForces.put(name, force);
            }
        }
    }

    @Override
    protected void postStep()
    {
        Collection<ClientThread> clients = game.getClients();
        Collection<BodyState> out = new ArrayList<BodyState>();

        //Add ball
        out.add(physicsWorld.getBodyState("$ball"));

        //Add buttons
        for(ClientThread ct: clients)
        {
            if(ct.getClient().getClientInfo().getType() == ClientInfo.Type.SPECTATOR)
                continue;

            String name = ct.getClient().getClientInfo().getName();
            BodyState bodyState = physicsWorld.getBodyState(name);

            if(bodyState != null)
            {
                Vec2 f = preStepForces.get(name);

                if(f != null)
                {
                    bodyState.forceX = f.x;
                    bodyState.forceY = f.y;
                    preStepForces.remove(name);
                }
                else
                {
                    bodyState.forceX = bodyState.forceY = 0f;
                }

                out.add(bodyState);
            }
        }
        
        physicsOutput.set(out);
    }
}
